#ifndef CFA_H
#define CFA_H
#include "typedef.h"
#include <set>
#include <map>
#include <string.h>
using namespace std;

//three types nodes
struct Node{
    vector<Node*> before;//Prev
    vector<Prop*> predicate;
    virtual ~Node(){ }
    virtual bool operator==(Node &other)=0;
};
/*
x = e | skip | x = id(e1, e2, ...) | return x | L: s | goto L | break | continue
*/
struct UniNode: Node{
    Expr* e1;					//
    Expr* e2;
    char statement[256];
    //function call
    char name[256];
    vector<Expr*> actualpara;
    Node *next;
    bool operator==(Node &other);
    //StmtType st;
    StmtType st;
};
/*
while b do  s | if b then s else s
*/
struct BinNode: Node{
    Prop *p;
    Node *_true, *_false;
    char statement[256];
    bool operator==(Node &other);
};
struct BadNode: Node{
    bool operator==(Node &other);
};
//recursive building graph type
struct ProgramConnectType{
    Node *init;
    vector<Node**> ends1;
    vector<Node*> ends2;
    //check
};
//CFA
class CFA{
    private:
        //function call
	char id[256];
	vector<VarExpr*> formal_parameter;
        //
        vector<Node*> LoopStart;
        vector<Node**> LoopEnd;
        //Lable Name
        map<Node*, char*> LabelSet;
        //origin
        Node* initNode;
        Node* finalNode;//BadNode

        Node* GetFinalNode(){ return finalNode; }
        void SetFinalNode(Node* X){ finalNode = X; }
        //write at x1.cc
        void RecursiveBinExpr(BinExpr*);
        InequProp* AssignExpr2Prop(Expr* , Expr*);
        //CFA(Prog)
        ProgramConnectType BuildCFA(Prog, Node*, Node*, map<Node*, char*>*);
        void PrintSingleNodeWithGraphviz(ofstream&, Node*);
        void PrintLogicType(LogicType);
        //void PrintProp(Prop*);
        void PrintPropType(PropType);
        void PrintOPType(OPType);
        //void PrintNode(Node*);
        void PrintBackNode(Node*);
        bool IsFound(vector<Node*> *, Node* );
        void RecursiveVerifyNode(Node*, set<Node*>&);
        void RecursiveVerifyBackNode(Node*, set<Node*>&);
        void GraphOPType(ofstream&, OPType);
        void GraphLogicType(ofstream&, LogicType);
        void GraphPropType(ofstream&, PropType);
        void GraphExpr(ofstream&, Expr*);
        void GraphProp(ofstream&, Prop*);
        void GraphNode(ofstream&, Node*, set<Node*>&);
        void GraphNode1(ofstream&, Node*, set<Node*>&, int, int);
        void RecursiveGraphNode(ofstream&, Node*, set<Node*>&);
        void RecursiveGraphNode1(ofstream&, Node*, set<Node*>&, int, int);
        //connect goto
        void ConnectGoto(map<Node*, char*>*);
        void SetUniNodeStatement(Node*, int, char*);
        void PrintExpr(Expr*);
        void PrintProp(Prop*);
        //void PrintNode(Node*);
        void SetInitNode(Node* X){ initNode = X; }
        void SetId(char* name){ strcpy(id, name); }				//
        void AddLableSet(pair<Node*, char*> p);					//
        void PrintCFA();
        void PrintBackCFA();


    public:
        void PrintNode(Node*);
        void CFA2Dot(const char*);
        // at cfa.cc
        void BuildGraph(){ BuildGraph(0); };
        void BuildGraph(int);
        Node* GetInitNode(){ return initNode; } 
        char* GetId(){ return id; }						//
        vector<VarExpr*> GetFormPara(){ return formal_parameter; }		//
        void AddFormPara(VarExpr* v){ formal_parameter.push_back(v); }		//
        map<Node*, char*> GetLableSet(){ return LabelSet; }			//
};
#endif
